#include "buffer.h"
#include <assert.h>
#include <sys/uio.h>
#include <unistd.h>

namespace zh
{
    void Buffer::initialize()
    {
        m_buffer.reserve(m_initSize);
        reset();
    }

    size_t Buffer::readableBytes() const
    {
        return m_writePosition - m_readPosition;
    }

    size_t Buffer::writeableBytes() const
    {
        return m_buffer.capacity() - m_writePosition;
    }

    ssize_t Buffer::readFD(int FD, int* saveErroNo)
    {
        char         extraBuffer[65535];
        struct iovec iov[2];

        size_t writeableLength = writeableBytes();

        iov[0].iov_base = beginPtr() + m_writePosition;
        iov[0].iov_len  = writeableLength;
        iov[1].iov_base = extraBuffer;
        iov[1].iov_len  = sizeof(extraBuffer);

        ssize_t length = readv(FD, iov, 2);

        if (length < 0)
        {
            *saveErroNo = errno;
        }
        else if (length <= writeableLength)
        {
            updateWritePtr(length);
        }
        else
        {
            m_writePosition = m_buffer.size();
            append(extraBuffer, length - writeableLength);
        }

        return length;
    }

    ssize_t Buffer::writeFD(int FD, int* saveErroNo)
    {
        size_t  readSize = readableBytes();
        ssize_t length   = write(FD, curReadPtr(), readSize);
        if (length < 0)
        {
            *saveErroNo = errno;
        }
        else
        {
            updateReadPtr(length);
        }
        return length;
    }

    void Buffer::append(const char* data, size_t length)
    {
        m_buffer.append(data, length);
        updateWritePtr(length);
    }

    void Buffer::append(const std::string& data)
    {
        m_buffer.append(data);
        updateWritePtr(data.length());
    }

    const char* Buffer::data() const
    {
        return curReadPtr();
    }

    size_t Buffer::length() const
    {
        return readableBytes();
    }

    void Buffer::reset()
    {
        m_readPosition  = 0;
        m_writePosition = 0;
        m_buffer.clear();
    }

    std::string Buffer::toString() const
    {
        return std::string(data(), length());
    }

    const char* Buffer::curReadPtr() const
    {
        return &m_buffer[0] + m_readPosition;
    }

    const char* Buffer::curWritePtr() const
    {
        return &m_buffer[0] + m_writePosition;
    }

    void Buffer::updateReadPtr(int length)
    {
        if (length < readableBytes())
        {
            m_readPosition += length;
        }
        else
        {
            reset();
        }
    }

    void Buffer::updateWritePtr(int length)
    {
        assert(length <= writeableBytes());
        m_writePosition += length;
    }

    char* Buffer::beginPtr()
    {
        return &m_buffer[0];
    }

    const char* Buffer::beginPtr() const
    {
        return &m_buffer[0];
    }
} // namespace zh